﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace OS.Instructions
{
    class GetData : Instruction
    {
        public GetData()
        {
        }//end default constructor

        /// <summary>
        /// Executes the the GD instruction
        /// </summary>
        public override void ExecuteGDInstruction()
        {
            Trace.WriteToTrace("Attempting to execute instruction: " + QueueManager.readyQueue.Peek().register_IR);

            //if no more data cards
            if (QueueManager.readyQueue.Peek().IsDEmpty())
            {
                QueueManager.readyQueue.Peek().terminationType = Termination.OutOfData;
            }
            else
            {
                int virtualAddress = int.Parse(QueueManager.readyQueue.Peek().register_IR[2].ToString() + QueueManager.readyQueue.Peek().register_IR[3].ToString());
                int page = virtualAddress/10;

                if (QueueManager.readyQueue.Peek().TLB.ContainsKey(page))
                {
                    //what type is it
                    if (QueueManager.readyQueue.Peek().TLB[page] is Frame)
                    {
                        //move to IO Queue
                        CPU.SI = 1;
                        Trace.WriteToTrace("Setting SI to 1 to request IO.");
                    }
                    else if (QueueManager.readyQueue.Peek().TLB[page] is Track)
                    {
                        Track trk = (Track) QueueManager.readyQueue.Peek().TLB[page];

                        //move to swap queue
                        Trace.WriteToTrace("Track " + trk.TrackID + " needs to be swapped into memory.");
                        Trace.WriteToTrace("Setting PI to 3 to request swap.");
                        CPU.PI = 3;
                    }
                }
                else if(QueueManager.readyQueue.Peek().frames < QueueManager.readyQueue.Peek().maxFrames)
                {
                    //get new frame
                    int frameNumber = EntryPoint.AllocateNewFrame(QueueManager.readyQueue.Peek());

                    if (frameNumber != -1)
                    {
                        Trace.WriteToTrace("Process has not used all of its frames. Allocating frame " + frameNumber + ".");

                        //frame is available
                        Frame newlyAllocatedFrame = new Frame(frameNumber);
                        newlyAllocatedFrame.LastAccessed = EntryPoint.cycle;

                        QueueManager.readyQueue.Peek().frames++;
                        Trace.WriteToTrace("Process " + QueueManager.readyQueue.Peek().groupID + " now has " + QueueManager.readyQueue.Peek().frames + " frames.");

                        //update TLB and page table
                        QueueManager.readyQueue.Peek().TLB[page] = newlyAllocatedFrame;
                        UserStorage.PhysicalMemory[QueueManager.readyQueue.Peek().register_PTR + page, 0] = newlyAllocatedFrame.ID.ToString();

                        Trace.WriteToTrace("Page table updated.");

                        //move to IO Queue
                        CPU.SI = 1;
                        Trace.WriteToTrace("Setting SI to 1 to request IO.");
                    }
                    else
                    {
                        Console.WriteLine("GetData.cs - No Frame Available");
                    }
                }
                else if (QueueManager.readyQueue.Peek().frames >= QueueManager.readyQueue.Peek().maxFrames)
                {
                    //move to swap queue
                    Trace.WriteToTrace("Need to swap a frame out of memory.");
                    Trace.WriteToTrace("Setting PI to 3 to request swap.");
                    CPU.PI = 3;
                }
            }

        }//end ExecuteInstruction

    }//end GetData
}//end OS.Instructions
